use super::task::{PROCESS, PROCESS_NUMBER};

#[no_mangle]
pub static mut current_process_nr: usize = 0;

#[no_mangle]
pub extern "C" fn schedule() -> usize {
    unsafe {
        // 当前进程的ticks未执行完成，则继续执行
        match PROCESS[current_process_nr].as_mut() {
            Some(p) => {
                if p.ticks > 0 {
                    p.ticks -= 1;
                    return current_process_nr;
                }
            },
            _ => {},
        };

        // 遍历所有的进程，选出最大的ticks对应的进程返回
        let mut max_ticks = 0;
        for i in 0..PROCESS_NUMBER {
            let ticks = PROCESS[i].as_mut().unwrap().ticks;
            if ticks > max_ticks {
                max_ticks = ticks;
                current_process_nr = i;
            }
        }

        if max_ticks > 0 {          // 找到非0的最大ticks进程，直接返回
            return current_process_nr;
        }

        // 如果所有进程的ticks都等于0了，那么重新给每个进程的ticks赋值为priority
        for i in 0..PROCESS_NUMBER {
            match PROCESS[i].as_mut() {
                Some(p) => {
                    p.ticks = p.priority;
                },
                _ => {},
            };
        }

        // 重新选出最大的ticks对应的进程
        for i in 0..PROCESS_NUMBER {
            let ticks = PROCESS[i].as_mut().unwrap().ticks;
            if ticks > max_ticks {
                max_ticks = ticks;
                current_process_nr = i;
            }
        }

        current_process_nr

    }
}

// 保存所有寄存器
#[no_mangle]
pub extern "C" fn save_all_regsiters(gs: u32, fs: u32, es: u32, ds: u32, // segment regs
    edi: u32, esi: u32, ebp: u32, kernel_esp: u32, ebx: u32, edx: u32, ecx: u32, eax: u32, // pusad
    _save_ret_addr : u32,   // ret address for _save, here not use
    eip: u32, cs: u32, eflags: u32, esp: u32, ss: u32) { // before enter interupt

    unsafe {
        match PROCESS[current_process_nr].as_mut() {
            Some(p) => {
                p.regs.gs = gs;
                p.regs.fs = fs;
                p.regs.es = es;
                p.regs.ds = ds;
                p.regs.edi = edi;
                p.regs.esi = esi;
                p.regs.ebp = ebp;
                p.regs.kernel_esp = kernel_esp;
                p.regs.ebx = ebx;
                p.regs.edx = edx;
                p.regs.ecx = ecx;
                p.regs.eax = eax;

                // following for segment regs
                p.regs.eip = eip;
                p.regs.cs = cs;
                p.regs.eflags = eflags;
                p.regs.esp = esp;
                p.regs.ss = ss;
            },
            _ => {},
        };
    }
}

// 保存返回值到eax
#[no_mangle]
pub extern "C" fn save_return_value_to_eax(eax: u32, nr: usize) {
    unsafe {
        match PROCESS[nr].as_mut() {
            Some(p) => {
                p.regs.eax = eax;
            },
            _ => {},
        };
    }
}

// 获取待调度进程的上下文起始位置
// !current_process_nr已经在schedule()中改变了即将被调度的进程
#[no_mangle]
pub extern "C" fn get_address_of_process() -> u32 {
    unsafe {
        (PROCESS[current_process_nr].as_mut().unwrap()) as *const _ as u32
    }
}

#[no_mangle]
pub static OFFSET_OF_LDT_SELECTOR: usize = 0x4A;  // LDT选择符相对结构体的偏移

#[no_mangle]
pub static OFFSET_OF_STACK_TOP: usize = 0x0;

#[no_mangle]
pub static OFFSET_OF_STACK_FOR_IRET: usize = 0x34;
